package qc.module.qms.service;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import qc.common.core.constants.QmsConstant;
import qc.common.core.enums.ResourceStatusFlagEnum;
import qc.common.core.enums.qms.QmsPointTimeSegmentEnum;
import qc.common.core.utils.LocalDateTimeUtil;
import qc.module.qms.algorithm.dto.QmsPointDto;
import qc.module.qms.entity.*;
import qc.module.qms.mapper.QmsPointMapper;
import qc.module.qms.service.alarm.QmsAlarmDataRuleService;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * QMS基础配置信息缓存获取Service，统一管理缓存的设置、更新、过期和获取
 * * 2025-9-20，实测在各Service中分散控制基础信息缓存的设置和读取有以下问题
 * * 1.在同一个Service中未使用@Cacheable注解的调用有@Cacheable注解的方法会导致不从缓存中获取数据（每次均要从数据库中读取数据）；
 * * 原因及解决方法参考：https://www.cnblogs.com/aaacarrot/p/17031498.html
 *
 * @author QuCheng Tech
 * @since 2025/9/20
 */
@Service
public class QmsBasicConfigCacheGetService {
    private static final Logger logger = LoggerFactory.getLogger(QmsBasicConfigCacheGetService.class);

    @Autowired
    private QmsPointService pointService;

    @Autowired
    private QmsElementService elementService;

    @Autowired
    private QmsStationRelationService stationRelationService;

    @Autowired
    private QmsStationPointService stationPointService;

    @Autowired
    private QmsStationCalcParamService stationCalcParamService;

    @Autowired
    private QmsAlarmDataRuleService alarmDataRuleService;

    /**
     * 根据指定站点编码、关联站点方向（to、from）、站点分类编码、扩展标记（可以为null）获取站点之间的关联关系集合
     * 返回的结果按照排序号Asc排序后返回
     *
     * @param stcd                       站点编码
     * @param isRelatedFrom              关联站点方向（to、from）
     * @param relateStationCategoryCode  关联的站点分类编码
     * @param relateStationCategoryCode, ext 扩展标记
     * @return java.util.List<qc.module.qms.entity.QmsStationRelation>
     * @author QuCheng Tech
     * @since 2025/9/22
     */
    public List<QmsStationRelation> getStationRelations(String stcd, boolean isRelatedFrom, String relateStationCategoryCode, String ext) {
        logger.debug("getStationRelations 根据站点编码获取站点关联关系集合，站点编码[" + stcd + "]，关联站点方向From[" + isRelatedFrom + "]，站点分类编码[" + relateStationCategoryCode + "]，扩展标记[" + ext + "]");
        //站点编码和关联的站点分类编码不能为空，扩展标记可以为空
        if (StringUtils.isNotBlank(stcd) && StringUtils.isNotBlank(relateStationCategoryCode)) {
            List<QmsStationRelation> allStationRelations = stationRelationService.getAllWithCache();
            if (allStationRelations != null && allStationRelations.size() > 0x0) {
                List<QmsStationRelation> filterStationRelations = null;
                //判断扩展标记是否为分别进行筛选
                if (StringUtils.isNotBlank(ext)) {
                    //有扩展标记，精确匹配扩展标记内容相等
                    if (isRelatedFrom == false)//匹配关联的站点
                        filterStationRelations = allStationRelations.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getStcd(), stcd)
                                && StringUtils.equalsIgnoreCase(p.getRelatectgcode(), relateStationCategoryCode) && StringUtils.equalsIgnoreCase(p.getExt(), ext)).collect(Collectors.toList());
                    else//匹配作为关联站点的From
                        filterStationRelations = allStationRelations.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getRelatestcd(), stcd)
                                && StringUtils.equalsIgnoreCase(p.getCtgcode(), relateStationCategoryCode) && StringUtils.equalsIgnoreCase(p.getExt(), ext)).collect(Collectors.toList());
                } else {
                    //扩展标记为空，要匹配扩展标记为空的关联关系
                    if (isRelatedFrom == false)//匹配关联的站点
                        filterStationRelations = allStationRelations.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getStcd(), stcd)
                                && StringUtils.equalsIgnoreCase(p.getRelatectgcode(), relateStationCategoryCode) && StringUtils.isBlank(p.getExt())).collect(Collectors.toList());
                    else//匹配作为关联站点的From
                        filterStationRelations = allStationRelations.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getRelatestcd(), stcd)
                                && StringUtils.equalsIgnoreCase(p.getCtgcode(), relateStationCategoryCode) && StringUtils.isBlank(p.getExt())).collect(Collectors.toList());
                }

                //判断有匹配的关联关系，按关联关系中的排序号排序后返回
                if (filterStationRelations != null && filterStationRelations.size() > 0x0) {
                    logger.debug("getStationRelations 根据站点编码获取站点关联关系集合，站点编码[" + stcd + "]，关联站点方向From[" + isRelatedFrom + "]，站点分类编码[" + relateStationCategoryCode + "]，扩展标记[" + ext + "]，获取到的站点关联关系共[" + filterStationRelations.size() + "]个");
                    return filterStationRelations.stream().sorted(Comparator.comparingInt(QmsStationRelation::getOdr)).collect(Collectors.toList());
                } else {
                    logger.debug("getStationRelations 根据站点编码获取站点关联关系集合，站点编码[" + stcd + "]，关联站点方向From[" + isRelatedFrom + "]，站点分类编码[" + relateStationCategoryCode + "]，扩展标记[" + ext + "]，获取到的站点关联关系集合为空");
                }

            } else {
                logger.debug("getStationRelations 根据站点编码获取站点关联关系集合，站点编码[" + stcd + "]，关联站点方向From[" + isRelatedFrom + "]，站点分类编码[" + relateStationCategoryCode + "]，扩展标记[" + ext + "]，所有站点之间关联关系集合为空");
            }
        }

        return null;
    }

    /**
     * 获取指定站点的主站点集合，获取传入站点作为备用站点的站点关联关系集合
     *
     * @param stcd    备用站点编码
     * @param ctgCode 站点分类编码，必须传入
     * @return java.util.List<qc.module.qms.entity.QmsStationRelation>
     * @author QuCheng Tech
     * @since 2025/9/23
     */
    public List<QmsStationRelation> getMasterStationRelations(String stcd, String ctgCode) {
        logger.debug("getMasterStationRelations 根据站点编码获取主用站点关系集合，站点编码[" + stcd + "]，站点分类编码[" + ctgCode + "]");
        //站点编码和站点分类编码不能为空，为空时直接返回null
        if (StringUtils.isNotBlank(stcd) && StringUtils.isNotBlank(ctgCode)) {
            List<QmsStationRelation> allStationRelations = stationRelationService.getAllWithCache();
            if (allStationRelations != null && allStationRelations.size() > 0x0) {
                //站点之间为主备关系时要求站点分类和关联站点分类相同，获取主站点时间传入的站点编码作为关联站点编码
                List<QmsStationRelation> filterStationRelations = allStationRelations.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getRelatestcd(), stcd)
                        && StringUtils.equalsIgnoreCase(p.getCtgcode(), ctgCode) && StringUtils.equalsIgnoreCase(p.getRelatectgcode(), ctgCode)
                        && StringUtils.equalsIgnoreCase(p.getExt(), QmsConstant.STATION_STANDBY_RELATION_EXT_STRING)).collect(Collectors.toList());
                if (filterStationRelations != null && filterStationRelations.size() > 0x0) {
                    logger.debug("getMasterStationRelations 根据站点编码获取主用站点关系集合，站点编码[" + stcd + "]，站点分类编码[" + ctgCode + "]，获取到的主用站点关系共[" + filterStationRelations.size() + "]个");
                    return filterStationRelations;
                } else {
                    logger.debug("getMasterStationRelations 根据站点编码获取主用站点关系集合，站点编码[" + stcd + "]，站点分类编码[" + ctgCode + "]，获取到的主用站点关系集合为空");
                }
            } else {
                logger.debug("getMasterStationRelations 根据站点编码获取主用站点关系集合，站点编码[" + stcd + "]，站点分类编码[" + ctgCode + "]，所有站点之间关联关系集合为空");
            }
        }

        return null;
    }

    /**
     * 获取指定站点的备用站点集合，获取传入站点作为主站点的站点关联关系集合
     *
     * @param stcd    主站点编码
     * @param ctgCode 站点分类编码，必须传入
     * @return java.util.List<qc.module.qms.entity.QmsStationRelation>
     * @author QuCheng Tech
     * @since 2025/9/23
     */
    public List<QmsStationRelation> getSlaveStationRelations(String stcd, String ctgCode) {
        logger.debug("getSlaveStationRelations 根据站点编码获取备用站点关系集合，站点编码[" + stcd + "]，站点分类编码[" + ctgCode + "]");
        //站点编码和站点分类编码不能为空，为空时直接返回null
        if (StringUtils.isNotBlank(stcd) && StringUtils.isNotBlank(ctgCode)) {
            List<QmsStationRelation> allStationRelations = stationRelationService.getAllWithCache();
            if (allStationRelations != null && allStationRelations.size() > 0x0) {
                //站点之间为主备关系时要求站点分类和关联站点分类相同，获取备用站点时间传入的站点编码作为站点编码
                List<QmsStationRelation> filterStationRelations = allStationRelations.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getStcd(), stcd)
                        && StringUtils.equalsIgnoreCase(p.getCtgcode(), ctgCode) && StringUtils.equalsIgnoreCase(p.getRelatectgcode(), ctgCode)
                        && StringUtils.equalsIgnoreCase(p.getExt(), QmsConstant.STATION_STANDBY_RELATION_EXT_STRING)).collect(Collectors.toList());
                if (filterStationRelations != null && filterStationRelations.size() > 0x0) {
                    logger.debug("getSlaveStationRelations 根据站点编码获取备用站点关系集合，站点编码[" + stcd + "]，站点分类编码[" + ctgCode + "]，获取到的备用站点关系共[" + filterStationRelations.size() + "]个");
                    return filterStationRelations;
                } else {
                    logger.debug("getSlaveStationRelations 根据站点编码获取备用站点关系集合，站点编码[" + stcd + "]，站点分类编码[" + ctgCode + "]，获取到的备用站点关系集合为空");
                }
            }
        } else {
            logger.debug("getSlaveStationRelations 根据站点编码获取备用站点关系集合，站点编码[" + stcd + "]，站点分类编码[" + ctgCode + "]，所有站点之间关联关系集合为空");
        }

        return null;
    }

    /**
     * 获取指定站点的冗余（多通道）站点集合
     *
     * @param stcd    站点编码
     * @param ctgCode 站点分类编码，必须传入
     * @return java.util.List<qc.module.qms.entity.QmsStationRelation>
     * @author QuCheng Tech
     * @since 2025/9/23
     */
    public List<QmsStationRelation> getMultiStationRelations(String stcd, String ctgCode) {
        logger.debug("getMultiStationRelations 根据站点编码获取冗余站点关系集合，站点编码[" + stcd + "]，站点分类编码[" + ctgCode + "]");
        //站点编码和站点分类编码不能为空，为空时直接返回null
        if (StringUtils.isNotBlank(stcd) && StringUtils.isNotBlank(ctgCode)) {
            List<QmsStationRelation> allStationRelations = stationRelationService.getAllWithCache();
            if (allStationRelations != null && allStationRelations.size() > 0x0) {
                //站点之间为冗余关系时要求站点分类和关联站点分类相同，传入的站点编码作为站点编码或者关联站点编码
                List<QmsStationRelation> filterStationRelations = allStationRelations.stream().filter(p ->
                        StringUtils.equalsIgnoreCase(p.getCtgcode(), ctgCode) && StringUtils.equalsIgnoreCase(p.getRelatectgcode(), ctgCode)
                                && StringUtils.equalsIgnoreCase(p.getExt(), QmsConstant.STATION_MULTI_RELATION_EXT_STRING)
                                && (StringUtils.equalsIgnoreCase(p.getStcd(), stcd) || StringUtils.equalsIgnoreCase(p.getRelatestcd(), stcd))).collect(Collectors.toList());
                if (filterStationRelations != null && filterStationRelations.size() > 0x0) {
                    logger.debug("getMultiStationRelations 根据站点编码获取冗余站点关系集合，站点编码[" + stcd + "]，站点分类编码[" + ctgCode + "]，获取到的冗余站点关系共[" + filterStationRelations.size() + "]个");
                    return filterStationRelations;
                } else {
                    logger.debug("getMultiStationRelations 根据站点编码获取冗余站点关系集合，站点编码[" + stcd + "]，站点分类编码[" + ctgCode + "]，获取到的冗余站点关系集合为空");
                }
            } else {
                logger.debug("getMultiStationRelations 根据站点编码获取冗余站点关系集合，站点编码[" + stcd + "]，站点分类编码[" + ctgCode + "]，所有站点之间关联关系集合为空");
            }
        }

        return null;
    }

    /**
     * 根据指定的站点编码、监测要素编码、扩展标记（可以为null）获取对应的站点与点号关联集合
     *
     * @param stcd        站点编码
     * @param elementCode 监测要素编码
     * @param ext         扩展标记，可以为空或null；完全匹配
     * @return List<QmsStationPoint> 按正常情况返回结果最多有1个元素
     * @author QuCheng Tech
     * @since 2025/9/19
     */
    public List<QmsStationPoint> getStationPointsByStcdAndElementCode(String stcd, String elementCode, String ext) {
        logger.debug("getStationPointsByStcdAndElementCode 根据站点编码和监测要素编码获取点号信息集合，站点编码[" + stcd + "]，监测要素编码[" + elementCode + "]，扩展标记[" + ext + "]");
        //站点编码和监测要素编码不能为空，为空时直接返回Null
        if (StringUtils.isNotBlank(stcd) && StringUtils.isNotBlank(elementCode)) {
            List<QmsStationPoint> allStationPoints = stationPointService.getAllWithCache();
            if (allStationPoints != null && allStationPoints.size() > 0x0) {
                //判断扩展标记是否为分别进行筛选
                if (StringUtils.isNotBlank(ext)) {
                    //有扩展标记，精确匹配扩展标记内容相等
                    List<QmsStationPoint> filterStationPoints = allStationPoints.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getStcd(), stcd)
                            && StringUtils.equalsIgnoreCase(p.getElecode(), elementCode) && StringUtils.equalsIgnoreCase(p.getExt(), ext)).collect(Collectors.toList());
                    if (filterStationPoints != null && filterStationPoints.size() > 0x0) {
                        logger.debug("getStationPointsByStcdAndElementCode 根据站点编码和监测要素编码获取点号信息集合，站点编码[" + stcd + "]，监测要素编码[" + elementCode + "]，扩展标记[" + ext + "]，获取到的站点与点号关联关系共[" + filterStationPoints.size() + "]个");
                        return filterStationPoints;
                    } else {
                        logger.debug("getStationPointsByStcdAndElementCode 根据站点编码和监测要素编码获取点号信息集合，站点编码[" + stcd + "]，监测要素编码[" + elementCode + "]，扩展标记[" + ext + "]，获取到的站点与点号关联关系集合为空");
                    }
                } else {
                    //扩展标记为空，要匹配扩展标记为空的关联关系
                    List<QmsStationPoint> filterStationPoints = allStationPoints.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getStcd(), stcd)
                            && StringUtils.equalsIgnoreCase(p.getElecode(), elementCode) && StringUtils.isBlank(p.getExt())).collect(Collectors.toList());
                    if (filterStationPoints != null && filterStationPoints.size() > 0x0) {
                        logger.debug("getStationPointsByStcdAndElementCode 根据站点编码和监测要素编码获取点号信息集合，站点编码[" + stcd + "]，监测要素编码[" + elementCode + "]，无扩展标记，获取到的站点与点号关联关系共[" + filterStationPoints.size() + "]个");
                        return filterStationPoints;
                    } else {
                        logger.debug("getStationPointsByStcdAndElementCode 根据站点编码和监测要素编码获取点号信息集合，站点编码[" + stcd + "]，监测要素编码[" + elementCode + "]，无扩展标记，获取到的站点与点号关联关系集合为空");
                    }
                }
            } else {
                logger.debug("getStationPointsByStcdAndElementCode 根据站点编码和监测要素编码获取点号信息集合，站点编码[" + stcd + "]，监测要素编码[" + elementCode + "]，扩展标记[" + ext + "]，所有站点与点号关联关系集合为空");
            }
        }

        return null;
    }

    /**
     * 在站点与点号关联关系中根据站点编码、监测要素编码和测点顺序号获取对应的点号Entity
     *
     * @param stcd        站点编码
     * @param elementCode 监测要素编码
     * @param ext         扩展标记，可以为空或null；完全匹配
     * @return qc.module.qms.algorithm.dto.QmsPointDto
     * @author QuCheng Tech
     * @since 2025/9/11
     */
    public QmsPoint getPointByStcdAndElementCode(String stcd, String elementCode, String ext) {
        logger.debug("getByStcdAndElementCode 根据站点编码和监测要素编码获取点号信息，站点编码[" + stcd + "]，监测要素编码[" + elementCode + "]，扩展标记[" + ext + "]");
        if (StringUtils.isNotBlank(stcd) && StringUtils.isNotBlank(elementCode)) {
            //先根据站点与点号关联关系获取匹配的关联集合，正常情况下集合应该只有1个元素，使用该元素中的点号进行点号信息获取；如果有关联关系集合有多个元素默认使用第1个元素
            List<QmsStationPoint> stationPoints = this.getStationPointsByStcdAndElementCode(stcd, elementCode, ext);
            if (stationPoints != null && stationPoints.size() > 0x0) {
                if (stationPoints.size() > 0x1) {
                    //如果获取到有多个对应的点号时生成警告日志
                    logger.warn("getByStcdAndElementCode 根据站点编码和监测要素编码获取点号信息，站点编码[" + stcd + "]，监测要素编码[" + elementCode
                            + "]，扩展标记[" + ext + "]，获取到的站点与点号关联关系有多个，关联关系数量为[" + stationPoints.size() + "]");
                }

                String pointid = stationPoints.get(0x0).getPointid();
                logger.debug("getByStcdAndElementCode 根据站点编码和监测要素编码获取点号信息，站点编码[" + stcd + "]，监测要素编码[" + elementCode
                        + "]，扩展标记[" + ext + "]，获取到的点号为[" + pointid + "]");
                //根据点号ID获取点号信息
                return getPoint(pointid);
            } else {
                logger.debug("getByStcdAndElementCode 根据站点编码和监测要素编码获取点号信息，站点编码[" + stcd + "]，监测要素编码[" + elementCode
                        + "]，扩展标记[" + ext + "]，获取到的站点与点号关联关系为空");
            }
        } else {
            logger.warn("getByStcdAndElementCode 根据站点编码和监测要素编码获取点号信息，站点编码[" + stcd + "]，监测要素编码[" + elementCode
                    + "]，扩展标记[" + ext + "]，站点编码或监测要素编码为空无法获取点号信息");
        }

        return null;
    }

    /**
     * 根据指定的点号ID获取点号对象DTO
     *
     * @param pointid 点号ID
     * @return qc.module.qms.algorithm.dto.QmsPointDto
     * @author QuCheng Tech
     * @since 2025/9/27
     */
    public QmsPointDto getPointDto(String pointid) {
        logger.debug("getPointDto 根据指定点号ID获取点号信息，点号ID[" + pointid + "]");
        if (StringUtils.isNotBlank(pointid)) {
            List<QmsPoint> allPoints = pointService.getAllWithCache();
            if (allPoints != null && allPoints.size() > 0x0) {
                Optional<QmsPoint> point = allPoints.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getPointid(), pointid)).findFirst();
                if (point != null && point.isPresent())
                    return QmsPointMapper.MAPPER.toDto(point.get());
            }
        }

        return null;
    }

    /**
     * 根据指定的点号ID获取点号对象Entity
     *
     * @param pointid 点号ID
     * @return qc.module.qms.algorithm.dto.QmsPoint
     * @author QuCheng Tech
     * @since 2025/9/27
     */
    public QmsPoint getPoint(String pointid) {
        logger.debug("getPoint 根据指定点号ID获取点号信息，点号ID[" + pointid + "]");
        if (StringUtils.isNotBlank(pointid)) {
            List<QmsPoint> allPoints = pointService.getAllWithCache();
            if (allPoints != null && allPoints.size() > 0x0) {
                Optional<QmsPoint> point = allPoints.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getPointid(), pointid)).findFirst();
                if (point != null && point.isPresent())
                    return point.get();
            }
        }

        return null;
    }

    /**
     * 获取指定时段类型的点号集合
     *
     * @param tmseg 时段类型
     * @return java.util.List<qc.module.qms.entity.QmsPoint>
     * @author QuCheng Tech
     * @since 2025/10/7
     */
    public List<QmsPoint> getTimeSegmentPoints(QmsPointTimeSegmentEnum tmseg) {
        logger.debug("getTimeSegmentPoints 根据指定时段类型获取点号集合，时段类型[" + tmseg + "]");
        if (tmseg != null && tmseg != QmsPointTimeSegmentEnum.UN_DEFINE) {
            List<QmsPoint> allPoints = pointService.getAllWithCache();
            if (allPoints != null && allPoints.size() > 0x0) {
                int intTmseg = tmseg.getIndex();
                //过滤时段类型中包含传入时段类型的点号
                List<QmsPoint> points = allPoints.stream().filter(p -> p.getTmsegs() != null && p.getTmsegs().intValue() > 0x0 && (p.getTmsegs().intValue() & intTmseg) == intTmseg).collect(Collectors.toList());
                if (points != null && points.size() > 0x0)
                    return points;
            }
        }

        return null;
    }

    /**
     * 根据指定的监测要素编码获取指定的监测要素对象Entity
     *
     * @param elecode 监测要素编码
     * @return qc.module.qms.entity.QmsElement
     * @author QuCheng Tech
     * @since 2025/9/29
     */
    public QmsElement getElement(String elecode) {
        logger.debug("getPoint 根据指定的监测要素编码获取指定的监测要素信息，监测要素编码[" + elecode + "]");
        if (StringUtils.isNotBlank(elecode)) {
            List<QmsElement> allElements = elementService.getAllWithCache();
            if (allElements != null && allElements.size() > 0x0) {
                Optional<QmsElement> element = allElements.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getElecode(), elecode)).findFirst();
                if (element != null && element.isPresent())
                    return element.get();
            }
        }

        return null;
    }

    /**
     * 获取参数项集合的参数值集合，优先从缓存数据中获取
     *
     * @param methodCode 计算方法编码
     * @param stcd       站点编码
     * @param paramCodes 参数编码集合
     * @return java.util.List<qc.module.qms.entity.QmsStationCalcParam>
     * @author QuCheng Tech
     * @since 2025/9/12
     */
    public List<QmsStationCalcParam> getStationCalcParams(String methodCode, String stcd, List<String> paramCodes) {
        //输入错误判定为不需要获取参数值
        if (StringUtils.isNotBlank(methodCode) && StringUtils.isNotBlank(stcd) && paramCodes != null && paramCodes.size() > 0x0) {
            logger.debug("getStationParamsWithCache 获取站点参数，计算方法[" + methodCode + "]，站点编码[" + stcd + "]，要获取的参数数量[" + paramCodes.size() + "]");
            List<QmsStationCalcParam> allParams = stationCalcParamService.getAllWithCache();
            //判断如果参数集合数量为1直接调用过滤方法返回数据，如果集合数量大于1需要组个遍历过滤
            if (paramCodes.size() == 0x1)
                return filterStationCalcParams(allParams, methodCode, stcd, paramCodes.get(0x0));

            List<QmsStationCalcParam> result = new ArrayList<>();

            for (String paramCode : paramCodes) {
                List<QmsStationCalcParam> paramValues = this.filterStationCalcParams(allParams, methodCode, stcd, paramCode);
                if (paramValues != null && paramValues.size() > 0x0)
                    result.addAll(paramValues);
            }

            //判断如果实际获取到的参数值集合数量＞0时才返回，否则返回null
            if (result.size() > 0x0)
                return result;
        }

        return null;
    }

    /**
     * 获取指定的一个参数项的参数值集合，优先从缓存数据中获取
     *
     * @param methodCode 计算方法编码
     * @param stcd       站点编码
     * @param paramCode  参数编码
     * @return java.util.List<qc.module.qms.entity.QmsStationCalcParam>
     * @author QuCheng Tech
     * @since 2025/9/12
     */
    public List<QmsStationCalcParam> getStationCalcParams(String methodCode, String stcd, String paramCode) {
        //输入错误判定为不需要获取参数值
        if (StringUtils.isNotBlank(methodCode) && StringUtils.isNotBlank(stcd) && StringUtils.isNotBlank(paramCode)) {
            List<QmsStationCalcParam> allParams = stationCalcParamService.getAllWithCache();
            return filterStationCalcParams(allParams, methodCode, stcd, paramCode);
        }

        return null;
    }

    /**
     * 从指定的参数值集合中筛选出指定的参数
     *
     * @param params     传入的参数值集合
     * @param methodCode 计算方法编码
     * @param stcd       站点编码
     * @param paramCode  参数编码
     * @return java.util.List<qc.module.qms.entity.QmsStationCalcParam>
     * @author QuCheng Tech
     * @since 2025/9/12
     */
    private List<QmsStationCalcParam> filterStationCalcParams(List<QmsStationCalcParam> params, String methodCode, String stcd, String paramCode) {
        //输入错误判定为不需要获取参数值
        if (params != null && params.size() > 0x0 && StringUtils.isNotBlank(methodCode) && StringUtils.isNotBlank(stcd) && StringUtils.isNotBlank(paramCode)) {
            List<QmsStationCalcParam> filterParams = params.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getMethodcode(), methodCode)
                    && StringUtils.equalsIgnoreCase(p.getStcd(), stcd) && StringUtils.equalsIgnoreCase(p.getParamcode(), paramCode)).collect(Collectors.toList());
            if (filterParams != null && filterParams.size() > 0x0) {
                logger.debug("filterParams 过滤筛选站点参数，计算方法[" + methodCode + "]，站点编码[" + stcd + "]，参数编码[" + paramCode + "]，筛选出的参数值集合数量[" + filterParams.size() + "]");
                return filterParams;
            } else {
                logger.debug("filterParams 过滤筛选站点参数，计算方法[" + methodCode + "]，站点编码[" + stcd + "]，参数编码[" + paramCode + "]，筛选出的参数值集合为空");
            }
        }

        return null;
    }

    /**
     * 获取有效的需要进行防误处理的点号数据值告警规则集合，只获取需要进行防误处理的规则，用于在保存点号数据前根据告警规则对数据值进行防误处理
     *
     * @param pointid  点号ID
     * @param tmseg    点号时段类型
     * @param datatime 点号数据时标，可以为null；为null表示不根据数据时标判断生效时间段，如果传入数据时标根据告警规则中设置的生效时间段进行过滤
     * @return java.util.List<qc.module.qms.entity.QmsAlarmDataRule>
     * @author QuCheng Tech
     * @since 2025/10/22
     */
    public List<QmsAlarmDataRule> getValidErrorProofPointDataAlarmRules(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime datatime) {
        return this.getValidPointDataAlarmRules(pointid, tmseg, datatime, true);
    }

    /**
     * 获取有效的不需要进行防误处理的点号数据值告警规则集合，只获取不需要进行防误处理的规则，用于在保存点号数据后根据点号数据消息触发获取告警规则判断是否需要进行告警处理
     *
     * @param pointid  点号ID
     * @param tmseg    点号时段类型
     * @param datatime 点号数据时标，可以为null；为null表示不根据数据时标判断生效时间段，如果传入数据时标根据告警规则中设置的生效时间段进行过滤
     * @return java.util.List<qc.module.qms.entity.QmsAlarmDataRule>
     * @author QuCheng Tech
     * @since 2025/10/22
     */
    public List<QmsAlarmDataRule> getValidNoErrorProofPointDataAlarmRules(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime datatime) {
        return this.getValidPointDataAlarmRules(pointid, tmseg, datatime, false);
    }

    /**
     * 获取有效的不需要进行防误处理的点号数据值告警规则集合，只获取不需要进行防误处理的规则，用于在保存点号数据后根据点号数据消息触发获取告警规则判断是否需要进行告警处理
     *
     * @param pointid    点号ID
     * @param tmseg      点号时段类型
     * @param datatime   点号数据时标，可以为null；为null表示不根据数据时标判断生效时间段，如果传入数据时标根据告警规则中设置的生效时间段进行过滤
     * @param errorProof 防误处理标记，为true表示只取防误处理为true的告警规则，为false表示只取防误处理为false的告警规则
     * @return java.util.List<qc.module.qms.entity.QmsAlarmDataRule>
     * @author QuCheng Tech
     * @since 2025/10/22
     */
    public List<QmsAlarmDataRule> getValidPointDataAlarmRules(String pointid, QmsPointTimeSegmentEnum tmseg, LocalDateTime datatime, boolean errorProof) {
        //先根据点号ID和时段类型获取关联的告警规则ID，再遍历告警规则ID集合逐个获取告警规则判断（是否有效、防误处理标记、生效时间段）
        List<QmsAlarmDataPoint> validAlarmRelations = this.getPointValidAlarmRelations(pointid, tmseg);
        if (validAlarmRelations != null && validAlarmRelations.size() > 0x0) {
            List<QmsAlarmDataRule> result = new LinkedList<>();

            for (QmsAlarmDataPoint relation : validAlarmRelations) {
                String ruleid = relation.getRuleid();
                QmsAlarmDataRule alarmRule = this.getAlarmRule(ruleid);
                if (alarmRule != null) {
                    //判断当前规则是否有效
                    if (alarmRule.getFlag() == ResourceStatusFlagEnum.NORMAL) {
                        //只过滤不需要防误处理的规则
                        if (alarmRule.getErrorproof() == errorProof) {
                            //如果有传入数据时标时间判断是否在生效时间段内
                            if (datatime != null) {
                                //如果生效起始时间在传入的时间点之后，当前告警规则不返回
                                if (alarmRule.getBegintm() != null && alarmRule.getBegintm().isAfter(datatime)) {
                                    logger.debug("getValidNoErrorProofPointDataAlarmRules 不使用该告警规则，规则ID[" + alarmRule.getRuleid() + "]，规则名称[" + alarmRule.getRulename()
                                            + "]，该告警规则有效起始时间[" + LocalDateTimeUtil.formatDateTime(alarmRule.getBegintm()) + "]＞数据时间点[" + LocalDateTimeUtil.formatDateTime(datatime) + "]");
                                    continue;
                                }

                                //如果生效截止时间在传入的时间点之前，当前告警规则不返回
                                if (alarmRule.getEndtm() != null && alarmRule.getEndtm().isBefore(datatime)) {
                                    logger.debug("getValidNoErrorProofPointDataAlarmRules 不使用该告警规则，规则ID[" + alarmRule.getRuleid() + "]，规则名称[" + alarmRule.getRulename()
                                            + "]，该告警规则有效截止时间[" + LocalDateTimeUtil.formatDateTime(alarmRule.getEndtm()) + "]＜数据时间点[" + LocalDateTimeUtil.formatDateTime(datatime) + "]");
                                    continue;
                                }

                                //如果每年重复的生效起始时间在传入的时间点之后，当前告警不返回;替换重复时间中的年份
                                if (alarmRule.getRepeatbegintm() != null && alarmRule.getRepeatbegintm().withYear(datatime.getYear()).isAfter(datatime)) {
                                    logger.debug("getValidNoErrorProofPointDataAlarmRules 不使用该告警规则，规则ID[" + alarmRule.getRuleid() + "]，规则名称[" + alarmRule.getRulename()
                                            + "]，该告警规则每年重复有效起始时间[" + LocalDateTimeUtil.formatDateTime(alarmRule.getRepeatbegintm()) + "]＞数据时间点[" + LocalDateTimeUtil.formatDateTime(datatime) + "]");
                                    continue;
                                }
                                //如果每年重复的生效截止时间在传入的时间点之前，当前告警规则不返回;替换重复时间中的年份
                                if (alarmRule.getRepeatendtm() != null && alarmRule.getRepeatendtm().withYear(datatime.getYear()).isBefore(datatime)) {
                                    logger.debug("getValidNoErrorProofPointDataAlarmRules 不使用该告警规则，规则ID[" + alarmRule.getRuleid() + "]，规则名称[" + alarmRule.getRulename()
                                            + "]，该告警规则每年重复有效截止时间[" + LocalDateTimeUtil.formatDateTime(alarmRule.getRepeatendtm()) + "]＜数据时间点[" + LocalDateTimeUtil.formatDateTime(datatime) + "]");
                                    continue;
                                }

                                //前面根据生效时间均判断通过，没有continue跳出本次告警规则的判断，表示当前告警规则有效添加到返回结果集合中
                                result.add(alarmRule);
                            }
                        }
                    }
                }
            }

            if (result.size() > 0x0)
                return result;
        }

        return null;
    }

    /**
     * 根据点号获取关联的有效告警规则（不管告警规则本身是否有效）
     *
     * @param pointid 点号ID
     * @param tmseg   点号时段类型
     * @return java.util.List<qc.module.qms.entity.QmsAlarmDataPoint>
     * @author QuCheng Tech
     * @since 2025/10/22
     */
    public List<QmsAlarmDataPoint> getPointValidAlarmRelations(String pointid, QmsPointTimeSegmentEnum tmseg) {
        //输入错误返回null，点号ID不能为空、时段类型不能为空或未定义
        if (StringUtils.isNotBlank(pointid) && tmseg != null && tmseg != QmsPointTimeSegmentEnum.UN_DEFINE) {
            List<QmsAlarmDataPoint> allRulePointRelations = alarmDataRuleService.getAllRulePointRelationsWithCache();
            if (allRulePointRelations != null && allRulePointRelations.size() > 0x0) {
                //根据点号和时段类型过滤，需要关联关系的状态为启用
                List<QmsAlarmDataPoint> pointRules = allRulePointRelations.stream().filter(p -> p.getFlag() == ResourceStatusFlagEnum.NORMAL
                        && StringUtils.equalsIgnoreCase(p.getPointid(), pointid) && p.getPointtmseg() == tmseg).collect(Collectors.toList());

                if (pointRules != null && pointRules.size() > 0x0)
                    return pointRules;
            }
        }

        return null;
    }

    /**
     * 获取指定告警规则与点号的关联关系集合
     *
     * @param ruleid    告警规则ID
     * @param onlyValid 是否只返回有效的关联关系，指定true时只返回有效的关联关系，指定false时不根据状态过滤
     * @return java.util.List<qc.module.qms.entity.QmsAlarmDataPoint>
     * @author QuCheng Tech
     * @since 2025/10/22
     */
    public List<QmsAlarmDataPoint> getAlarmRulePointRelations(String ruleid, boolean onlyValid) {
        //输入错误返回null，告警规则ID不能为空
        if (StringUtils.isNotBlank(ruleid)) {
            List<QmsAlarmDataPoint> allRulePointRelations = alarmDataRuleService.getAllRulePointRelationsWithCache();
            if (allRulePointRelations != null && allRulePointRelations.size() > 0x0) {
                if (onlyValid == true) {
                    //根据点号和时段类型过滤，需要关联关系的状态为启用
                    List<QmsAlarmDataPoint> pointRules = allRulePointRelations.stream().filter(p -> p.getFlag() == ResourceStatusFlagEnum.NORMAL
                            && StringUtils.equalsIgnoreCase(p.getRuleid(), ruleid)).collect(Collectors.toList());

                    if (pointRules != null && pointRules.size() > 0x0)
                        return pointRules;
                } else {
                    //不管关联关系的状态
                    List<QmsAlarmDataPoint> pointRules = allRulePointRelations.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getRuleid(), ruleid)).collect(Collectors.toList());

                    if (pointRules != null && pointRules.size() > 0x0)
                        return pointRules;
                }
            }
        }

        return null;
    }

    /**
     * 获取指定规则ID的告警规则
     *
     * @param ruleid 告警规则ID
     * @return qc.module.qms.entity.QmsAlarmDataRule
     * @author QuCheng Tech
     * @since 2025/10/22
     */
    public QmsAlarmDataRule getAlarmRule(String ruleid) {
        if (StringUtils.isNotBlank(ruleid)) {
            List<QmsAlarmDataRule> allRules = alarmDataRuleService.getAllRulesWithCache();
            if (allRules != null && allRules.size() > 0x0) {
                Optional<QmsAlarmDataRule> alarmRule = allRules.stream().filter(p -> StringUtils.equalsIgnoreCase(p.getRuleid(), ruleid)).findFirst();

                if (alarmRule != null && alarmRule.isPresent())
                    return alarmRule.get();
            }
        }

        return null;
    }
}
